from django.utils.timezone import now
from drf_spectacular.utils import extend_schema
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from rest_framework_simplejwt.serializers import TokenRefreshSerializer
from rest_framework_simplejwt.tokens import AccessToken, RefreshToken
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

from accounts.decorators import register_action_permission
from .models import UserDevice
from .serializers import (
    DeviceLogoutSerializer,
    EmptySerializer,
    
    TokenObtainRequestSerializer,
    TokenRefreshRequestSerializer,
    TokenRefreshResponseSerializer,
    TokenResponseSerializer,
    UserDeviceSerializer,
    UserIdQuerySerializer,  # Added this line
)
from core.serializers import MessageResponseSerializer
from django.db.models import F  # Added this line

class CustomTokenRefreshSerializer(TokenRefreshSerializer):
    def validate(self, attrs):
        # 获取 refresh token
        refresh = RefreshToken(attrs['refresh'])
        
        # 检查设备状态
        device_id = refresh.get('device_id')
        user_id = refresh.get('user_id')
        token_version = refresh.get('token_version')
        
        if device_id and user_id:
            device = UserDevice.objects.filter(
                device_id=device_id,
                user_id=user_id
            ).first()
            
            if not device:
                raise InvalidToken({
                    'detail': '设备不存在',
                    'code': 'token_not_valid'
                })
                
            if not device.is_active:
                raise InvalidToken({
                    'detail': '设备已注销',
                    'code': 'token_not_valid'
                })
            
            if token_version != device.token_version:
                raise InvalidToken({
                    'detail': '令牌已失效',
                    'code': 'token_not_valid'
                })
                
            # 更新最后登录时间
            device.last_login = now()
            device.save(update_fields=['last_login'])
        
        # 生成新的 access token
        access = refresh.access_token
        
        data = {'access': str(access)}
        
        if 'refresh' in attrs:
            data['refresh'] = str(refresh)
            
        return data

class CustomTokenRefreshView(TokenRefreshView):
    serializer_class = TokenRefreshRequestSerializer
    
    @extend_schema(
        request=TokenRefreshRequestSerializer,
        responses={200: TokenRefreshResponseSerializer}
    )
    def post(self, request, *args, **kwargs):
        # 获取新令牌
        response = super().post(request, *args, **kwargs)
        
        if response.status_code == 200:
            try:
                # 从旧的刷新令牌中获取设备 ID
                old_refresh = RefreshToken(request.data['refresh'])
                device_id = old_refresh.get('device_id')
                
                if device_id:
                    # 创建新的访问令牌，包含设备 ID
                    new_access = response.data.get('access')
                    if new_access:
                        access_token = AccessToken(new_access)
                        access_token['device_id'] = device_id
                        response.data['access'] = str(access_token)
                    
            except Exception as e:
                print(f"Error copying device_id to new token: {str(e)}")
        
        return response

class CustomTokenObtainPairView(TokenObtainPairView):
    username_field = 'username'
    
    def get_serializer_class(self):
        if self.request.method == 'POST':
            if getattr(self, 'swagger_fake_view', False):
                return TokenResponseSerializer
        return super().get_serializer_class()
    
    @extend_schema(
        request=TokenObtainRequestSerializer,
        responses={
            200: TokenResponseSerializer,
            401: MessageResponseSerializer
        },
    )
    def post(self, request, *args, **kwargs):
        response = super().post(request, *args, **kwargs)
        
        if response.status_code == 200:
            # 使用序列化器验证凭据并获取用户
            serializer = TokenObtainRequestSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            user = serializer.user
            
            # 解析 User-Agent
            ua_string = request.META.get('HTTP_USER_AGENT', '')
            ua_info = parse_user_agent(ua_string)
            
            # 获取 IP 地址
            x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
            if x_forwarded_for:
                ip = x_forwarded_for.split(',')[0]
            else:
                ip = request.META.get('REMOTE_ADDR')
            
            # 根据设备特征生成设备 ID
            device_id = generate_device_id(user, ua_info, ip)
            
            # 创建或更新设备记录
            device, created = UserDevice.objects.get_or_create(
                device_id=device_id,
                user=user,
                defaults={
                    'device_name': f"{ua_info['browser']} on {ua_info['os']}",
                    'device_type': ua_info['device_type'],
                    'browser': ua_info['browser'],
                    'os': ua_info['os'],
                    'ip_address': ip,
                    'is_active': True,
                }
            )
            
            print(f"[Login] {'Created' if created else 'Updated'} device {device_id} for user {user.username}")
            print(f"[Login] Device status: active={device.is_active}, version={device.token_version}")

            # 更新设备信息
            device.device_name = f"{ua_info['browser']} on {ua_info['os']}"
            device.device_type = ua_info['device_type']
            device.browser = ua_info['browser']
            device.os = ua_info['os']
            device.ip_address = ip
            device.is_active = True
            device.last_login = now()
            device.token_version += 1
            device.save(update_fields=[
                'device_name', 'device_type', 'browser', 
                'os', 'ip_address', 'is_active', 'last_login',
                'token_version'
            ])
            
            print(f"[Login] Updated device info: active={device.is_active}, version={device.token_version}")

            # 在 token 中添加设备信息
            access = AccessToken(response.data['access'])
            access['device_id'] = device_id
            access['token_version'] = device.token_version
            response.data['access'] = str(access)

            refresh = RefreshToken(response.data['refresh'])
            refresh['device_id'] = device_id
            refresh['token_version'] = device.token_version
            response.data['refresh'] = str(refresh)

            # 在响应中添加设备ID
            response.data['device_id'] = device_id
            print(f"[Login] Response data: {response.data}")
        
        return response

    # def get_user(self, credentials):
    #     from django.contrib.auth import authenticate
    #     return authenticate(**credentials)

class DeviceViewSet(viewsets.ModelViewSet):
    serializer_class = UserDeviceSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """
        返回用户的所有设备，包括非活动设备
        """
        # 如果指定了用户ID，则获取该用户的设备
        user_id = self.request.query_params.get('user_id')
        if user_id:
            return UserDevice.objects.filter(user_id=user_id)
        # 否则返回当前用户的设备
        return UserDevice.objects.filter(user=self.request.user)
    
    def get_serializer_class(self):
        if self.action in ['logout', 'logout_all', 'logout_user_device', 'logout_user_all']:
            return EmptySerializer
        return UserDeviceSerializer
    
    @extend_schema(
        parameters=[UserIdQuerySerializer],
        responses={200: UserDeviceSerializer(many=True)}
    )
    def list(self, request):
        """
        获取设备列表。
        如果提供了user_id查询参数，则返回指定用户的设备列表；
        否则返回当前用户的设备列表。
        """
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    @extend_schema(
        request=EmptySerializer,
        responses={200: MessageResponseSerializer, 403: MessageResponseSerializer, 404: MessageResponseSerializer}
    )
    @action(detail=True, methods=['post'])
    def logout(self, request, pk=None):
        """注销当前用户的指定设备"""
        try:
            device = UserDevice.objects.get(device_id=pk, user=request.user)
        except UserDevice.DoesNotExist:
            return Response(
                {'detail': '设备不存在或未授权'}, 
                status=status.HTTP_404_NOT_FOUND
            )
            
        if device.user != request.user:
            return Response(
                {'detail': '未授权'}, 
                status=status.HTTP_403_FORBIDDEN
            )
            
        # 更新设备状态
        device.is_active = False
        device.token_version += 1
        device.save()
        
        return Response({'detail': '设备已注销'})

    @extend_schema(
        request=EmptySerializer,
        responses={200: MessageResponseSerializer}
    )
    @action(detail=False, methods=['post'])
    def logout_all(self, request):
        """注销当前用户的所有设备（除了当前设备）"""
        current_device_id = request.auth.get('device_id') if request.auth else None
        
        # 获取当前用户的所有其他设备
        devices = UserDevice.objects.filter(user=request.user)
        if current_device_id:
            devices = devices.exclude(device_id=current_device_id)
            
        # 批量更新设备状态
        devices.update(
            is_active=False,
            token_version=F('token_version') + 1
        )
        
        return Response({'detail': '所有设备已注销'})

    @extend_schema(
        request=EmptySerializer,
        responses={200: MessageResponseSerializer, 403: MessageResponseSerializer, 404: MessageResponseSerializer}
    )
    @action(detail=True, methods=['post'])
    def logout_user_device(self, request, pk=None):
        """注销指定用户的指定设备"""
        try:
            device = UserDevice.objects.get(device_id=pk)
        except UserDevice.DoesNotExist:
            return Response(
                {'detail': '设备不存在'}, 
                status=status.HTTP_404_NOT_FOUND
            )
            
        # 更新设备状态
        device.is_active = False
        device.token_version += 1
        device.save()
        
        return Response({'detail': '设备已注销'})

    @extend_schema(
        request=EmptySerializer,
        responses={200: MessageResponseSerializer}
    )
    @action(detail=False, methods=['post'])
    def logout_user_all(self, request):
        """注销指定用户的所有设备"""
        user_id = request.query_params.get('user_id')
        if not user_id:
            return Response(
                {'detail': '缺少user_id参数'}, 
                status=status.HTTP_400_BAD_REQUEST
            )
            
        # 批量更新设备状态
        UserDevice.objects.filter(user_id=user_id).update(
            is_active=False,
            token_version=F('token_version') + 1
        )
        
        return Response({'detail': '所有设备已注销'})

def parse_user_agent(ua_string):
    """简单的 User-Agent 解析函数"""
    ua_string = ua_string.lower()
    
    # 检测设备类型
    if any(mobile in ua_string for mobile in ['mobile', 'android', 'iphone', 'ipad', 'windows phone']):
        device_type = 'mobile'
    elif 'tablet' in ua_string:
        device_type = 'tablet'
    else:
        device_type = 'desktop'
    
    # 检测浏览器
    browsers = {
        'chrome': 'Chrome',
        'firefox': 'Firefox',
        'safari': 'Safari',
        'edge': 'Edge',
        'opera': 'Opera',
        'ie': 'Internet Explorer'
    }
    browser = next((browsers[b] for b in browsers if b in ua_string), 'Unknown Browser')
    
    # 检测操作系统
    systems = {
        'windows': 'Windows',
        'macintosh': 'MacOS',
        'mac os': 'MacOS',
        'linux': 'Linux',
        'android': 'Android',
        'ios': 'iOS'
    }
    os = next((systems[s] for s in systems if s in ua_string), 'Unknown OS')
    
    return {
        'device_type': device_type,
        'browser': browser,
        'os': os
    }

def generate_device_id(user, ua_info, ip_address):
    """根据用户和设备信息生成唯一标识"""
    import hashlib
    
    # 组合用户 ID 和设备信息
    device_info = f"{user.id}:{ua_info['browser']}:{ua_info['os']}:{ip_address}"
    
    # 生成哈希
    return hashlib.md5(device_info.encode()).hexdigest()
